package com.hc.jdbc.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.hc.jdbc.util.JdbcUtilsV2;

public class BaseDao {
    /**
     * 封装简化非DQL语句
     * @param sql 带占位符的sql语句
     * @param params 占位符的值
     * @return 执行影响的行数
     * @throws SQLException
     */
    public int executeUpdate(String sql, Object... params) throws SQLException {
//获取连接
        Connection connection = JdbcUtilsV2.getConnection();
        PreparedStatement statement = connection.prepareStatement(sql);
//占位符赋值
//可变参数可以当做数组使用
        for (int i = 0; i < params.length; i++) {
            statement.setObject(i+1, params[i]);
        }
//发送sql语句
//DML类型
        int rows = statement.executeUpdate();
        statement.close();
//是否回收连接需要考虑是不是事务
        if(connection.getAutoCommit()) {
//如果是自动提交，说明没有开启事务，正常回收连接
            connection.close();
        }
        return rows;
    }

/*
 * DQL语句封装方法 -> 返回值 是什么类型呢？
 * 并不是list<Map> map key和value自定义，不用先设定好
 * map 没有数据校验机制
 * map 不支持反射操作
 *
 * 数据库数据 -> java实体类
 *
 * table表
 * t_user
 * id
 * account
 * password
 * nickname
 *
 * java类
 * User
 * id
 * account
 * password
 * nickname
 * 表中的一行数据 对应 java类的一个对象
 * 表中的多行数据 对应 List<Java实体类> list
 *
 * <T> 声明一个泛型，不确定类型
 * 1.确定泛型 User.class T = User
 * 2.要使用反射技术属性赋值
 * public <T> List<T> executeQuery(Class<T> clazz, String sql, Object...
 params)
 * @throws SQLException
 * @throws IllegalAccessException
 * @throws InstantiationException
 * @throws SecurityException
 * @throws NoSuchMethodException
 * @throws InvocationTargetException
 * @throws IllegalArgumentException
 **/
public <T> List<T> executeQuery(Class<T> clazz, String sql, Object...
        params) throws Exception {
    Connection connection = JdbcUtilsV2.getConnection();
    PreparedStatement statement = connection.prepareStatement(sql);
    for (int i = 0; i < params.length; i++) {
        statement.setObject(i+1, params[i]);
    }
    ResultSet resultSet = statement.executeQuery();
//结果集解析
    List<T> list = new ArrayList<T>();
//获取列信息对象
    ResultSetMetaData metaData = resultSet.getMetaData();
//获取列的总数
    int columnCount = metaData.getColumnCount();

    while(resultSet.next()) {
        T t = clazz.newInstance();//调用类的无参构造函数实例化对象
// T t = clazz.getDeclaredConstructor().newInstance();//jdk1.9以后，用这个
//一行数据对应一个 T 类型的对象
//自动遍历列，注意：要从1开始，并且小于等于总列数
        for (int i = 1; i <= columnCount; i++) {
//对象的属性值
            Object value = resultSet.getObject(i);
//获取制定下角标的列名称
            String columnLabel = metaData.getColumnLabel(i);
//反射，给对象的属性赋值
            Field field = clazz.getDeclaredField(columnLabel);
            field.setAccessible(true);//属性可以设置，打破private的限制
/**
 * 参数1：要赋值的对象
 * 参数2：具体的属性值
 */
            field.set(t, value);
        }
        list.add(t);
    }
    return list;
}
}